home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 52
/
Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso
/
Aminet
/
misc
/
emu
/
Apex-src.lha
/
INTA.68K
< prev
next >
Wrap
Text File
|
2001-09-30
|
70KB
|
2,523 lines
;INTA.68K AUG-05-90
;XPL intrinsics for the 68000
;Written by Loren Blaney
;This is derived from 6502 code written by P.J.R. Boyle.
;
;REVISION HISTORY:
;DEC-84, Original, known as: INT.68K.
;DEC-85, Added floating point intrinsics.
;FEB-86, Modified for 32-bit operations for DFM engineering.
;MAR-86, Modified for double-precision floating point.
;SEP-86, Converted to ASM68K conventions and modified.
;OCT-86, Modified to run in supervisor mode and to interface cleanly
; with assembly language.
;NOV-86, Modified for second terminal (device 1)
;DEC-86, Added OPENF intrinsic and removed FASAVE
;FEB-87, Fixed test for file too long.
;MAR-87, Added graphics routines for the Amiga.
; Added 32-bit multiply and divide.
; Added intrinsics: SWAP_W, PEEK, POKE, EXT_L, and CARRY.
;APR-87, Changed string convention, BLIT(FROM, TO, SIZE), remainder.
;MAY-87, Cleaned up graphics intrinsics.
;JUL-87, Speed up CLEAR and VIEW, fix infinite loop in LINE clipping.
;AUG-87, Speed up LINE slightly.
;NOV-87, Fix line clipping.
;JUN-88, Modified for increased screen height (240/480), fixed CLEAR
; intrinsic.
;JUL-07-88, Fix point plot on screens larger than 640x400.
;AUG-09-89, Fix glitch in VIEW & CLEAR intrinsics (removed CLR.Ws).
;AUG-05-90, Fixed CLEAR to work for all bit map dimensions, and added
; BUTTON and JOYSTICK.
;
;NOTES:
;These intrinsics, unlike subroutines in general, may destroy the
; contents of registers D0 and A6. If, in the interest of speed,
; registers are not saved and restored, this should be clearly stated
; as part of the operation of the subroutine.
;
NOLIST
INCLUDE SYSPAG ;Get system page definitions
LIST
;-----------------------------------------------------------------------
;INTRINSIC JUMP TABLE
ORG INTTBL ;Compiler expects the jump table here
JMP ABS.L ;0
JMP RAN.L ;1
JMP REM.L ;2
JMP RESERV.L ;3
JMP SWAP.L ;4
JMP EXTEND.L ;5
JMP RESTAR.L ;6
JMP CHIN.L ;7
JMP CHOUT.L ;8
JMP CRLF.L ;9
JMP INTIN.L ;10
JMP INTOUT.L ;11
JMP TEXT.L ;12
JMP OPENI.L ;13
JMP OPENO.L ;14
JMP CLOSE.L ;15
JMP ABORT.L ;16
JMP TRAP.L ;17
JMP FREE.L ;18
JMP RERUN.L ;19
JMP GETHP.L ;20
JMP SETHP.L ;21
JMP GETERR.L ;22
JMP CURSOR.L ;23
JMP SCAN.L ;24
JMP SETRUN.L ;25
JMP HEXIN.L ;26
JMP HEXOUT.L ;27
JMP CHAIN.L ;28
JMP OPENF.L ;29
JMP WRITE.L ;30
JMP READ.L ;31
JMP BADINT.L ;TESTPT.L ;32
JMP FGET.L ;33
JMP BADINT.L ;FASAVE.L ;34
JMP FSAVE.L ;35
JMP BLIT.L ;36 BLIT(FROM, TO, BYTES)
JMP BUTTON.L ;37
JMP JOYSTICK.L ;38
JMP BADINT.L ;SOUND.L ;39
JMP CLEAR.L ;40
JMP POINT.L ;41
JMP LINE.L ;42
JMP MOVE.L ;43
JMP BADINT.L ;44
JMP BADINT.L ;BLOCK.L ;45
JMP RLRES.L ;46
JMP RLIN.L ;47
JMP RLOUT.L ;48
JMP FLOAT.L ;49
JMP FIX.L ;50
JMP RLABS.L ;51
JMP FORMAT.L ;52
JMP SQRT.L ;53
JMP LN.L ;54
JMP EXP.L ;55
JMP SIN.L ;56
JMP ATAN2.L ;57
JMP MOD.L ;58
JMP LOG.L ;59
JMP COS.L ;60
JMP TAN.L ;61
JMP ASIN.L ;62
JMP ACOS.L ;63
JMP BACKUP.L ;64
JMP BADINT.L ;HICHAR.L ;65
JMP BADINT.L ;PEEK.L ;66
JMP BADINT.L ;POKE.L ;67
JMP BADINT.L ;68
JMP BADINT.L ;69
JMP BADINT.L ;70
JMP BADINT.L ;71
JMP BADINT.L ;72
JMP BADINT.L ;73
JMP BADINT.L ;74
JMP BADINT.L ;75
JMP BADINT.L ;76
JMP BADINT.L ;77
JMP BADINT.L ;78
JMP BADINT.L ;79
JMP BADINT.L ;80
JMP BADINT.L ;81
JMP BADINT.L ;82
JMP BADINT.L ;83
JMP BADINT.L ;84
JMP BADINT.L ;85
JMP BADINT.L ;86
JMP BADINT.L ;87
JMP BADINT.L ;88
JMP BADINT.L ;89
JMP BADINT.L ;90
JMP BADINT.L ;91
JMP BADINT.L ;92
JMP BADINT.L ;93
JMP BADINT.L ;94
JMP BADINT.L ;95
JMP BADINT.L ;96
JMP BADINT.L ;97
JMP BADINT.L ;98
JMP BADINT.L ;99
JMP BADINT.L ;100
JMP BADINT.L ;101
JMP BADINT.L ;102
JMP BADINT.L ;103
JMP BADINT.L ;104
JMP BADINT.L ;105
JMP BADINT.L ;106
JMP WAITVB.L ;107
JMP BITMAP.L ;108 BITMAP(ADDR, WIDTH, HEIGHT, DEPTH)
JMP BITMAP2.L ;109 BITMAP2(MAGX, Y, OFFX, Y, INVX, Y)
JMP VIEW.L ;110 VIEW(ADDR, BPLCON0)
JMP PALETTE.L ;111 PALETTE(N, VAL)
JMP CARRY.L ;112
JMP PEEK_W.L ;113
JMP POKE_W.L ;114
JMP PEEK_L.L ;115
JMP POKE_L.L ;116
JMP SWAP_W.L ;117
JMP EXT_L.L ;118
JMP CURSOR1.L ;119
JMP BUTES1.L ;120
JMP SHOCUR1.L ;121
JMP DEVINFO.L ;122
JMP UNTINFO.L ;123
JMP BUTES.L ;124
JMP GETKEY.L ;125
JMP KEYHIT.L ;126
JMP SHOCUR.L ;127
REMAIN DS.L 1 ;Remainder of most recent divide
;32-bit multiply routines:
JMP MUL1.L ;D1:= D1 * D2
JMP MUL2.L ;D2:= D2 * D3
JMP MUL3.L ;D3:= D3 * D4
JMP MUL4.L ;D4:= D4 * D5
JMP MUL5.L ;D5:= D5 * D6
JMP MUL6.L ;D6:= D6 * D7
;32-bit divide routines:
JMP DIV1.L ;D1:= D1 / D2
JMP DIV2.L ;D2:= D2 / D3
JMP DIV3.L ;D3:= D3 / D4
JMP DIV4.L ;D4:= D4 / D5
JMP DIV5.L ;D5:= D5 / D6
JMP DIV6.L ;D6:= D6 / D7
;-----------------------------------------------------------------------
;All INT.68K variables are stored here. The 68020 compiler must know the
; location of REMAIN. The rest are grouped here for convenience when
; they are saved and restored by the multitasking exec.
;
RANK DC.L 2537 ;Random number seeds (initialized at
RANL DC.L 5149 ; load time)
RANM DC.L 7026 ;Random number that is actually output
BACKFL DS.B 1 ;Backup flag, used to re-read last char
LASTCH DS.B 1 ;The last character read by BYTEIN
RASTER DC.L $60000 ;Location of current bit map
WIDTH DC.L 640 ;Dimensions of RASTER in pixels
HEIGHT DC.L 240
DEPTH DC.L 1
MAGX DC.L 0 ;Parameters affecting how coordinates
MAGY DC.L 0 ; are remapped from specified to
OFFSETX DC.L 0 ; actual hardware values
OFFSETY DC.L 0
INVERTX DC.L 0
INVERTY DC.L 0
X0 DC.L 0 ;Graphics coordinates (these might have
Y0 DC.L 0 ; been remapped by the above parameters)
X1 DC.L 0
Y1 DC.L 0
COLOR DC.L 0 ;Only lowest byte specifies color reg.
MODES EQU COLOR+2 ;Bit 0: complement
;Bit 1: fast (i.e. don't clear zeros)
TEXTURE EQU COLOR ;For dotted lines, etc. Ones indicate
; where points are NOT plotted. 16 bits.
IF @ # $B96
ERROR - AMIGAHAN.68K EXPECTS THESE VALUES TO BE AT $B5A
ENDIF
IF @ >= $C00
ERROR - CHIN3, CHOUT3
ENDIF
ORG $C10 ;KLUDGE TO SKIP CHIN3, CHOUT3
COPLST1 DS.L 32 ;(7 bit planes *2 +2) *2 = 32
COPLST2 DS.L 32 ;Second list is used when first is busy
COPFLAG DC.B 0 ;Flag used to double-buffer copper lists
ORG MEMTOP -$4000
;----------------------------------------------------------------------
;MULTIPLY ROUTINES:
;
;Routine to multiply two signed, 32-bit numbers and produce a signed,
; 32-bit product. D1:= D1 * D2 or D1:= X * Y.
; Registers D0, D2, and A6 are destroyed.
;
MUL1 MOVEA.W D1,A6 ;(4) Save XL
MOVE.L D1,D0 ;(4) Save XH
MULU D2,D1 ;(70) D1:= XL * YL
SWAP D0 ;(4)
MULU D2,D0 ;(70) D0:= XH * YL
SWAP D1 ;(4) Accumulator is word swapped
ADD.W D0,D1 ;(4) Accumulate high words in D1
MOVE.W A6,D0 ;(4)
SWAP D2 ;(4)
MULU D2,D0 ;(70) D0:= XL * YH
ADD.W D0,D1 ;(4) Accumulate high word in D1
SWAP D1 ;(4) Restore proper order
RTS ;(16) Return product in D1
;(262) Total cycles, worst case
;D2:= D2 * D3
; Registers D0, D3, and A6 are destroyed.
MUL2 MOVEA.W D2,A6
MOVE.L D2,D0
MULU D3,D2
SWAP D0
MULU D3,D0
SWAP D2
ADD.W D0,D2
MOVE.W A6,D0
SWAP D3
MULU D3,D0
ADD.W D0,D2
SWAP D2
RTS
;D3:= D3 * D4
; Registers D0, D4, and A6 are destroyed.
MUL3 MOVEA.W D3,A6
MOVE.L D3,D0
MULU D4,D3
SWAP D0
MULU D4,D0
SWAP D3
ADD.W D0,D3
MOVE.W A6,D0
SWAP D4
MULU D4,D0
ADD.W D0,D3
SWAP D3
RTS
;D4:= D4 * D5
; Registers D0, D5, and A6 are destroyed.
MUL4 MOVEA.W D4,A6
MOVE.L D4,D0
MULU D5,D4
SWAP D0
MULU D5,D0
SWAP D4
ADD.W D0,D4
MOVE.W A6,D0
SWAP D5
MULU D5,D0
ADD.W D0,D4
SWAP D4
RTS
;D5:= D5 * D6
; Registers D0, D6, and A6 are destroyed.
MUL5 MOVEA.W D5,A6
MOVE.L D5,D0
MULU D6,D5
SWAP D0
MULU D6,D0
SWAP D5
ADD.W D0,D5
MOVE.W A6,D0
SWAP D6
MULU D6,D0
ADD.W D0,D5
SWAP D5
RTS
;D6:= D6 * D7
; Registers D0, D7, and A6 are destroyed.
MUL6 MOVEA.W D6,A6
MOVE.L D6,D0
MULU D7,D6
SWAP D0
MULU D7,D0
SWAP D6
ADD.W D0,D6
MOVE.W A6,D0
SWAP D7
MULU D7,D0
ADD.W D0,D6
SWAP D6
RTS
;----------------------------------------------------------------------
;DIVIDE ROUTINES:
;
;D2:= D2 /D3
; Registers D0, D3, and A6 are destroyed.
DIV2 EXG D2,D1 ;Get numerator and save D1
EXG D3,D2 ;Get denominator and save D2
BSR.S DIV1 ;D1:= D1 /D2
MOVE.L D3,D2 ;Restore D2
EXG D1,D2 ;Get quotient and restore D1
RTS
;D3:= D3 /D4
; Registers D0, D4, and A6 are destroyed.
DIV3 EXG D3,D1
EXG D4,D2
BSR.S DIV1
MOVE.L D4,D2
EXG D1,D3
RTS
;D4:= D4 /D5
; Registers D0, D5, and A6 are destroyed.
DIV4 EXG D4,D1
EXG D5,D2
BSR.S DIV1
MOVE.L D5,D2
EXG D1,D4
RTS
;D5:= D5 /D6
; Registers D0, D6, and A6 are destroyed.
DIV5 EXG D5,D1
EXG D6,D2
BSR.S DIV1
MOVE.L D6,D2
EXG D1,D5
RTS
;D6:= D6 /D7
; Registers D0, D7, and A6 are destroyed.
DIV6 EXG D6,D1
EXG D7,D2
BSR.S DIV1
MOVE.L D7,D2
EXG D1,D6
RTS
;----------------------------------------------------------------------
;Routine to do a signed, 32-bit divide.
; D1:= D1 /D2 remainder is in REMAIN
; (32 bits):= (32 bits) / (32 bits), remainder (32 bits)
; Registers D0, D2, and A6 are destroyed.
;
DIV1 MOVE.L D2,D0 ;(4) Get a copy of the denominator
BGT.S DIV20 ;(10) Branch if it is greater than one
BEQ.S DIV10 ;Branch if divide by zero
NEG.L D2 ;Else, make denominator positive
BSR.S DIV20 ;Do divide
NEG.L D1 ;Reverse sign of quotient
RTS
DIV10 JSR VERROR
ASCII '100 - DIVIDE BY 0'
DC.B 0
MOVEQ #$FFFFFFFF,D1 ;Return the best answer:
LSR.L #1,D1 ;D1:= $7FFFFFFF
MOVE.L D2,REMAIN ; quotient = maximum, remainder = 0
RTS
DIV20 TST.L D1 ;(4) Is the numerator positive?
BPL.S DIV30 ;(10) Branch if so
NEG.L D1 ;Otherwise make it positive
BSR.S DIV30 ;Do divide
NEG.L D1 ;Make quotient negative
NEG.L REMAIN ;Make remainder negative
RTS
;D1:= D1 / D2
;Positive, 31-bit values.
DIV30 SWAP D0 ;Is denominator more than 16 bits?
TST.W D0
BNE.S DIV50 ;(8) Branch if so
DIVU D2,D1 ;(140) Attempt a simple divide
BVS.S DIV40 ;(8) Branch if it didn't work
MOVEQ #0,D2 ;(4) Clear high word for the remainder
SWAP D1 ;(4) Get the remainder into D2
MOVE.W D1,D2 ;(4)
MOVE.L D2,REMAIN ;(16)
CLR.W D1 ;(4) Clear high word of quotient
SWAP D1 ;(4)
RTS
; D1:= D1 /D2
; (32 bits):= (32 bits) / (16 bits)
;
; N NH *2^16 + NL NH REM *2^16 + NL
; --- = --------------- = ---- *2^16 + ----------------
; D D D D
;
; Where:
; N = The 32-bit numerator
; D = The 16-bit denominator
; NH = The high word of the numerator
; NL = The low word of the numerator
; REM = The 16-bit remainder from NH/D
;
; Note: (REM *2^16 + NL) / D does not overflow because
; (REM *2^16 + NL) < (D *2^16).
;
DIV40 MOVE.W D1,D0 ;Save the low word, NL
CLR.W D1
SWAP D1 ;Get the high word, NH
DIVU D2,D1 ; /D
MOVEA.W D1,A6 ;Save the high quotient, QH, in A6
MOVE.W D0,D1 ;QL = [REM *2^16 + NL] /D
DIVU D2,D1
SWAP D1 ;Quotient = QH *2^16 + QL
MOVEQ #0,D2
MOVE.W D1,D2 ;Save remainder
MOVE.L D2,REMAIN ;(16)
MOVE.W A6,D1 ;Combine QH with QL
SWAP D1
RTS
;Check for some trivial cases
; D1:= D1 /D2
DIV50 CMP.L D1,D2 ;Compare denominator to numerator
BLT.S DIV70
BEQ.S DIV60
MOVE.L D1,REMAIN ;Remainder = numerator
MOVEQ #0,D1 ;Quotient = 0
RTS
DIV60 MOVEQ #1,D1 ;Quotient = 1
MOVEQ #0,D2
MOVE.L D2,REMAIN ;Remainder = 0
RTS
;Handle the non-trivial case: LONG / LONG.
; D1:= D1 /D2, $10000 <= D2 < D1
;The basic idea here is to shift D2 and D1 right until D2 < $10000. This
; allows the DIVU instruction to be used, which provides a quotient that
; is very nearly correct -- worst case it is only one count too large.
;
DIV70 MOVE.L D1,-(SP) ;Save numerator
MOVEA.L D2,A6 ;Save denominator
MOVEQ #15,D0 ;Scan for the most significant set bit
SWAP D2 ; in the denominator
CMPI.W #$100,D2
BGE.S DIV80
MOVEQ #7,D0
DIV80
DIV85 BTST D0,D2
DBNE D0,DIV85
SWAP D2 ;Restore D2
ADDQ.B #1,D0
LSR.L D0,D2 ;Shift numerator and denominator right
LSR.L D0,D1 ; until the denominator fits in a word
DIVU D2,D1 ;Divide the truncated values
EXT.L D1 ;Zero the high word of the quotient
;Test numerator = Original denominator * truncated quotient
; (32) * (16) => (32)
MOVE.L A6,D2 ;Get original denominator
MULU D1,D2 ;Times tructated quotient
MOVE.L A6,D0 ;Multiply the high word of denominator
SWAP D0
MULU D1,D0
SWAP D2 ;Add partial products
ADD.W D0,D2
SWAP D2
;Remainder = original numerator - test numerator
NEG.L D2 ;Subtract test numerator
ADD.L (SP)+,D2 ;Add the original numerator
BGE.S DIV90 ;Branch if cool
SUBQ.W #1,D1 ;Adjust quotient
ADD.L A6,D2 ;Adjust remainder (add orig denominator)
DIV90
MOVE.L D2,REMAIN ;(16)
RTS
;----------------------------------------------------------------------
;Illegal intrinsic handler. (Note: this would be improved a tremendous
; amount if it said where it came from.)
;
BADINT JSR VERROR
ASCII '105 - ILLEGAL INTRINSIC'
DC.B 0
RTS
;-----------------------------------------------------------------------
;0
;Return the absolute value of the argument in D0.
; I:= ABS(J)
;
ABS MOVE.L (A5),D0
BPL.S ABS10
NEG.L D0
ABS10 RTS
;-----------------------------------------------------------------------
;1
;Return a random number, between 0 and the argument-1, in D0.
; If the argument = 0, then the seeds are reinitialized (for a
; repeatable sequence). If the argument < 0 then randomize and
; return a positive value between 0 and -(argument-1).
; I:= RAN(10)
; *** THIS IS CURRENTLY A 16-BIT OPERATION ***
;
RAN TST.L (A5) ;Is the argument = 0
BNE.S RANF10 ;Branch if not
BSR.S RANINI ;Initialize seeds
MOVEQ #0,D0 ;Return 0
BRA.S RANF90
RANF10 BPL.S RANF20 ;Branch if the argument is positive
MOVE.L HASH,RANM ;Randomize with keyboard spinner
NEG.L (A5) ;Return a positive random number
RANF20 BSR.S RANDOM ;Get a random number
DIVS 2(A5),D0 ;D0:= REM(D0 / 2(A5))
CLR.W D0 ;Clear quotient
SWAP D0 ;Get remainder into low word
RANF90 RTS
;
;Initialize the random number seeds
;
RANINI MOVE.L #2537,RANK ;Reinitialize the seeds
MOVE.L #5149,RANL
MOVE.L #7026,RANM
RTS
;
;Return a random number, between 0 and 10860, in D0.
;*** should be increased to 32 bit values *** ????
;
MODK EQU 10909 ;Modulo values (prime numbers)
MODL EQU 10891
MODM EQU 10861
RANDOM MOVE.L RANK,D0 ;RANK:=2*RANK modulo MODK
ADD.L D0,D0
CMP.L #MODK,D0
BLT.S RAN10
SUB.L #MODK,D0
RAN10 MOVE.L D0,RANK
MOVE.L RANL,D0 ;RANL:=2*RANL modulo MODL
ADD.L D0,D0
CMP.L #MODL,D0
BLT.S RAN20
SUB.L #MODL,D0
RAN20 MOVE.L D0,RANL
ADD.L RANK,D0 ;RANM:= (RANK+RANL+RANM) modulo MODM
ADD.L RANM,D0
RAN30 CMP.L #MODM,D0
BLT.S RAN99
SUB.L #MODM,D0
BRA.S RAN30
RAN99 MOVE.L D0,RANM
RTS
;-----------------------------------------------------------------------
;2
;Return the remainder of the last integer divide in D0.
; The sign of the remainder is always the same as the dividend unless
; the dividend is equal to zero.
; I:= REM(5/3)
;
REM MOVE.L REMAIN,D0 ;Get the remainder
RTS
;-----------------------------------------------------------------------
;3
;Reserve heap space for an array (A5:= A5 + <ARG>).
; ADDR:= RESERVE(BYTES)
; The starting (low) address of the reserved space in returned in D0.
;WARNING: This assumes that the heap and the stack are arranged so that
; they grow toward each other.
;
RESERV MOVE.L A5,D0 ;Return the base address in D0
BTST #0,3(A5) ;Make sure he is reserving an even
BEQ.S RES10 ; number of bytes, branch if so
ADDQ.B #1,3(A5) ;Add one more byte to make it even
RES10
ADDA.L (A5),A5 ;Add the argument number of bytes
; to the heap pointer (A5)
CMPA.L SP,A5 ;Check for memory overflow
BLO.S RES90
JSR VERROR
ASCII '102 - MEMORY OVERFLOW'
DC.B 0
RES90 RTS
;-----------------------------------------------------------------------
;4
;Swap bytes in a word.
; The swapped bytes of the argument are returned in D0.
; I:= SWAP($3412)
;
SWAP MOVE.L (A5),D0
ROL.W #8,D0
RTS
;-----------------------------------------------------------------------
;5
;Extend the sign bit of a byte to 32 bits (a long word).
; The sign-extended argument is returned in D0.
; I:= EXTEND($80)
;
EXTEND MOVE.B 3(A5),D0
EXT.W D0
EXT.L D0
RTS
;-----------------------------------------------------------------------
;6
;Restart the current (XPL) program.
; RESTART
;
RESTAR ST RERUNF ;Set the RERUN flag
CLR.L ERRLOC ;Indicate no errors
MOVEA.L STACK,SP ;Set the stack pointer
MOVEA.L HEAP,A5 ;Set the heap pointer
JSR VRSTRT ;Call the current program
JSR VSHOERR ;Display any errors
JMP VEXIT ;Take the program's exit vector
;-----------------------------------------------------------------------
;7
;Return a byte from input device DEV in D0.
; BYTE:= CHIN(DEV);
;
CHIN MOVE.B 3(A5),DEVICE ;Get the device number
BRA BYTEIN ;(PBRA) returns with byte in D0
;-----------------------------------------------------------------------
;8
;Send a byte to device DEV.
; CHOUT(DEV,BYTE);
; A6 and D0 are destroyed.
;
CHOUT MOVE.B 3(A5),DEVICE ;Get the device number
MOVE.B 7(A5),D0 ;Get the character
MOVEA.W #12,A6 ;Set the function code = CHOUT
JMP VDEVHAN ;(PJMP) output D0
;-----------------------------------------------------------------------
;9
;Send a "new line" command to DEV
; CRLF(DEV)
; A6 and D0 are destroyed.
;
CRLF MOVE.B 3(A5),DEVICE ;Get the device number
MOVEQ #CR,D0 ;CR = new line (LF is not used)
MOVEA.W #12,A6 ;Set the function code = CHOUT
JMP VDEVHAN ;(PJMP) do I/O
;-----------------------------------------------------------------------
;10
;Get a signed, decimal ASCII string from device DEV, convert it to a
; binary long word, and return it in D0.
; I:= INTIN(DEV)
;
INTIN MOVE.B 3(A5),DEVICE ;Get the device number
BRA INTI ;(PBRA) return the integer in D0
;-----------------------------------------------------------------------
;11
;Convert a 32-bit integer to a signed, decimal ASCII string and send it
; out to device DEV.
; INTOUT(DEV,I)
; D0 is destroyed.
;
INTOUT MOVE.B 3(A5),DEVICE ;Get the device number
MOVE.L 4(A5),D0 ;Get the integer
BRA INTO ;(PBRA) output the integer
;-----------------------------------------------------------------------
;12
;Output the ASCII string at address ADDR to I/O device DEV.
; TEXT(DEV,ADDR)
; A6 is destroyed.
;
TEXT MOVE.B 3(A5),DEVICE ;Get the device number
MOVEA.L 4(A5),A6 ;Get the address
BRA TEXTO ;(PBRA) output the string
;-----------------------------------------------------------------------
;13
;Open (initialize) a device for input.
; OPENI(DEV)
; A6 is destroyed.
;
OPENI MOVE.B 3(A5),DEVICE ;Get the device number
MOVEA.W #0,A6 ;Set the function code = OPENI
JMP VDEVHAN ;(PJMP) do I/O
;-----------------------------------------------------------------------
;14
;Open (initialize) a device for output.
; OPENO(DEV)
; A6 is destroyed.
;
OPENO MOVE.B 3(A5),DEVICE ;Get the device number
MOVEA.W #4,A6 ;Set the function code = OPENO
JMP VDEVHAN ;(PJMP) do I/O
;-----------------------------------------------------------------------
;15
;Close an output device (flushes buffers, etc.)
; CLOSE(DEV)
; A6 is destroyed.
;
CLOSE MOVE.B 3(A5),DEVICE ;Get the device number
MOVEA.W #16,A6 ;Set the function code = CLOSE
JMP VDEVHAN ;(PJMP) do I/O
;-----------------------------------------------------------------------
;16
;Abort the XPL program (same as a CTRL-P exit)
; ABORT
;
ABORT JMP VABORT
;-----------------------------------------------------------------------
;17
;Turn system error trapping on or off as indicated.
; TRAP('FALSE')
;
TRAP MOVE.B #FALSE,ERRTRAP ;Assume it is false (=0)
TST.L (A5)
BEQ.S TR90
ST ERRTRAP ;Set it true if any bit was set
TR90 RTS
;-----------------------------------------------------------------------
;18
;Return the amount of free space left in the heap and the stack.
; WARNING: It is assumed here that the stack and the heap are set up
; such that they grow toward each other.
; I := FREE
;
FREE MOVE.L SP,D0 ;RETURN (SP - A5)
SUB.L A5,D0
RTS
;-----------------------------------------------------------------------
;19
;Return the rerun flag
; FLAG := RERUN
;
RERUN MOVE.B RERUNF,D0
EXT.W D0
EXT.L D0
RTS
;-----------------------------------------------------------------------
;20
;Return the heap pointer
; ADDR := GETHP
;
GETHP MOVE.L A5,D0
RTS
;-----------------------------------------------------------------------
;21
;Set the heap pointer.
; SETHP($2000)
; (The user had better have a good idea of the functioning of XPL before
; dinging with the heap pointer or he will surely bomb himself!)
; A6 is destroyed.
;
SETHP MOVEA.L (A5),A5
RTS
;-----------------------------------------------------------------------
;22
;Return 'TRUE' if an error has been detected. (Traps must be turned off
; using intrinsic 17 for this to occur.)
; I:= GETERR;
;
GETERR MOVEQ #FALSE,D0 ;Assume no error
TST.L ERRLOC ;ERRLOC = 0 if no error is detected
BEQ.S GE10
MOVEQ #TRUE,D0
GE10 CLR.L ERRLOC ;Clear any possible error
RTS
;-----------------------------------------------------------------------
;23
;Move cursor of device 0 to column X, line Y. Upper left corner is
; X,Y = 0,0.
; CURSOR(X,Y)
; A6 is destroyed.
;
CURSOR MOVE.B #0,DEVICE ;Set to device number 0
MOVE.B 3(A5),D0 ;Get X position
ROL.W #8,D0 ;Put it into high byte of D0
MOVE.B 7(A5),D0 ;Get Y position into low byte
MOVEA.W #28,A6 ;Set function code = "position cursor"
JMP VDEVHAN ;(PJMP) do I/O
;-----------------------------------------------------------------------
;24
;Scan the directory for a file name and return its start and end blocks
; SCAN(UNIT, INFO, NAME)
; UNIT - unit number (0-7)
; INFO - the address of a 2-integer array where the starting and
; ending blocks are returned
; NAME - the address of a 12-byte file name
; (note: the 11th byte cannot have its MSB set)
;
SCAN MOVE.B 3(A5),UNIT ;Get the unit argument
MOVEA.L 8(A5),A6 ;Point A6 to the file name
JSR VFSCAN ;Scan for the name (heap is not used)
MOVEA.L 4(A5),A6 ;Get the address of the info array
MOVE.L BLKNO,(A6) ;Put the start and end blocks into it
MOVE.L ENDBLK,4(A6)
RTS
;-----------------------------------------------------------------------
;25
;Set the RERUN flag
; SETRUN('TRUE')
;
SETRUN MOVE.B #FALSE,RERUNF ;Assume it is false (=0)
TST.L (A5)
BEQ.S SR90
ST RERUNF ;Set it true if any bit was set
SR90 RTS
;-----------------------------------------------------------------------
;26
;Get a hex ASCII string from device DEV, convert it to a binary word,
; and return it in D0.
; I:= HEXIN(DEV)
;
HEXIN MOVE.B 3(A5),DEVICE ;Get the device number
BRA HEXI ;(PBRA) get the hex integer in D0
;-----------------------------------------------------------------------
;27
;Convert a 32-bit integer to an unsigned, hex ASCII string and send it
; out to device DEV.
; HEXOUT(DEV,I)
;
HEXOUT MOVE.B 3(A5),DEVICE ;Get the device number
MOVE.L 4(A5),D0 ;Get the integer
BRA HEXO ;(PBRA) output the hex integer
;-----------------------------------------------------------------------
;28
;Run a .SAV file
; CHAIN(UNIT, BLKNO)
;
CHAIN MOVE.B 3(A5),UNIT ;Get the arguments
MOVE.L 4(A5),BLKNO
JMP VFRUN ;Go run it (never returns)
;-----------------------------------------------------------------------
;29
;Open a disk file for input
; OPENF(UNIT, INFO);
; UNIT - unit number (0-7)
; INFO - the address of a 2-integer array containing the starting
; and ending blocks (usually gotten from SCAN)
;
OPENF MOVE.B 3(A5),INUNT ;Set the input unit
MOVEA.L 4(A5),A6 ;Get the address of the array
MOVE.L (A6),INLBLK ;Set the starting block number
MOVE.L 4(A6),INHBLK ;Set the ending block number
MOVE.B #1,INFLG ;1 = SETUP
MOVE.B #3,DEVICE ;Open the disk file for input
MOVEA.W #0,A6 ;Set the function code = OPENI
JMP VDEVHAN ;(PJMP) do I/O
;-----------------------------------------------------------------------
;30
;Write the memory at BUFFER to UNIT for SIZE many BLOCKS
; WRITE(UNIT, BLOCK, BUFFER, SIZE)
;
WRITE MOVE.B 3(A5),UNIT ;Get the arguments
MOVE.L 4(A5),BLKNO
MOVE.L 8(A5),FADDR
MOVE.L 12(A5),NBLKS
MOVEA.W #12,A6 ;Set "write" function code
JMP VUNTHAN ;(PJMP) perform the unit function code
;-----------------------------------------------------------------------
;31
;Read into the memory at BUFFER FROM UNIT for SIZE many BLOCKS
; READ(UNIT, BLOCK, BUFFER, SIZE)
;
READ MOVE.B 3(A5),UNIT ;Get the arguments
MOVE.L 4(A5),BLKNO
MOVE.L 8(A5),FADDR
MOVE.L 12(A5),NBLKS
MOVEA.W #8,A6 ;Set "read" function code
JMP VUNTHAN ;(PJMP) perform the unit function code
;-----------------------------------------------------------------------
;32
;COLOR:=TESTPT(X, Y)
TESTPT RTS
;-----------------------------------------------------------------------
;33
;Load a memory image and enter the monitor
; FGET(UNIT,BLKNO)
;
FGET MOVE.B 3(A5),UNIT ;Get arguments
MOVE.L 4(A5),BLKNO
JMP VFGET ;(Never returns)
;-----------------------------------------------------------------------
;35
;Write a memory image for a .SAV file
; FSAVE(UNIT,BLKNO)
;
FSAVE MOVE.B 3(A5),UNIT ;Get arguments
MOVE.L 4(A5),BLKNO
JMP VFSAVE ;(Never returns)
;-----------------------------------------------------------------------
;36
;Routine to quickly move a block of memory.
; Move SIZE many bytes from FROM to TO
; BLIT(FROM, TO, SIZE)
; (Don't use the blitter because it only works with chip memory.)
;
BLIT MOVEM.L D1/A0,-(SP) ;Save register(s)
;Get arguments:
MOVEA.L (A5),A0 ; FROM
MOVEA.L 4(A5),A6 ; TO
MOVE.L 8(A5),D0 ; SIZE
MOVE.L D0,D1 ;Put the high 16 bits of SIZE into
SWAP D1 ; a second counter, D1
CMPA.L A0,A6 ;If TO > FROM (i.e: moving forward in
BEQ.S BLIT90 ; memory) then don't branch
BLO.S BLIT20 ;Enter loop checking for SIZE = 0
ADDA.L D0,A6 ;Move starting at the end of the block
ADDA.L D0,A0 ;Add SIZE to TO and FROM
BRA.S BLIT40 ;Enter loop checking for SIZE = 0
BLIT10 MOVE.B (A0)+,(A6)+ ;Move block backward, pointers forward
BLIT20 DBF D0,BLIT10 ;Loop until D0 = -1
DBF D1,BLIT10 ; and also D1 = -1
BRA.S BLIT90 ;Exit
BLIT30 MOVE.B -(A0),-(A6) ;Move block forward, pointers backward
BLIT40 DBF D0,BLIT30 ;Loop until D0 = -1
DBF D1,BLIT30 ; and also D1 = -1
BLIT90 MOVEM.L (SP)+,D1/A0 ;Restore register(s)
RTS
;----------------------------------------------------------------------
;37
;Return "true" if specified mouse button is pressed
; BOOLEAN:=BUTTON(NUMBER)
;
CIAA EQU $BFE001
BUTTON MOVE.W 2(A5),D0 ;0 = Port 1, left button
BNE.S BUT10
BTST #6,CIAA.L
BEQ.S BTRUE
BRA.S BFALSE
BUT10
CMPI.W #1,D0 ;1 = Port 1, right button
BNE.S BUT20
NOP ;NOT IMPLEMENTED
BRA.S BFALSE
BUT20
CMPI.W #2,D0 ;2 = Port 2, left button
BNE.S BUT30
BTST #7,CIAA.L
BEQ.S BTRUE
BRA.S BFALSE
BUT30
CMPI.W #3,D0 ;3 = Port 2, right button
BNE.S BFALSE
NOP ;NOT IMPLEMENTED
BFALSE MOVEQ #FALSE,D0 ;Return "false"
RTS
BTRUE MOVEQ #TRUE,D0 ;Return "true"
RTS
;----------------------------------------------------------------------
;38
;Returns "true" if specified joystick direction (DIR) is pressed
; if JOYSTICK(DIR) then ...
;
; LEFT PORT RIGHT PORT
;
; 2 6
; | |
; 3 ---+--- 1 7 ---+--- 5
; | |
; 0 4
;
JOY0DAT EQU $DFF00A ;Chip register addresses
JOY1DAT EQU $DFF00C
JOYSTICK
MOVEM.W D1/D2,-(SP) ;Save registers
MOVE.W 2(A5),D0 ;Get specified direction, DIR
MOVE.W JOY1DAT.L,D1 ;Assume right port
BTST #2,D0
BNE.S JOY05
MOVE.W JOY0DAT.L,D1 ;Use left port
JOY05
BTST #0,D0 ;if DIR & 1 then...
BEQ.S JOY20
BTST #1,D0 ;if DIR & 2 then
BEQ.S JOY10
BTST #9,D1 ; return (DATA & $0200) # 0 \3 <--
BRA.S JOY90
JOY10
BTST #1,D1 ; else return (DATA & $0002) # 0 \1 -->
BRA.S JOY90
JOY20
MOVE.W D1,D2 ;DATA:= DATA>>1 | DATA;
LSR.W #1,D2
EOR.W D2,D1
BTST #1,D0 ;if DIR & 2 then
BEQ.S JOY30
BTST #8,D1 ; return (DATA & $0100) # 0 \2 Forward
BRA.S JOY90
JOY30
BTST #0,D1 ; else return (DATA & $0001) # 0 \0 Back
JOY90 MOVEM.W (SP)+,D1/D2 ;Restore regs without changing status
BNE.S JTRUE
MOVEQ #FALSE,D0 ;Return "false"
RTS
JTRUE MOVEQ #TRUE,D0 ;Return "true"
RTS
;-----------------------------------------------------------------------
;39
;SOUND(VOLUME, CYCLES, PERIOD);
SOUND RTS
;-----------------------------------------------------------------------
;40
;Clear the current graphics bit map.
;
CLEAR BRA DOCLEAR ;(PBRA)
;-----------------------------------------------------------------------
;41
;Plot a point at X,Y on the current bit map. "COLOR" selects a color
; register. It also specifys complement and "fast" modes.
; POINT(X, Y, COLOR)
;
POINT MOVE.L (A5),D0
BSR REMAPX
MOVE.L D0,X0
MOVE.L 4(A5),D0
BSR REMAPY
MOVE.L D0,Y0
MOVE.L 8(A5),COLOR
BRA DOPOINT ;(PBRA) Plot a point at X0,Y0
;-----------------------------------------------------------------------
;42
;Draw a straight line from X0,Y0 to X,Y on the current bit map. "COLOR"
; selects a color register, modes, and 16 bits of texture. The texture
; is complemented, for example, 16 zero bits gives a solid line.
; LINE(X, Y, COLOR)
;
LINE MOVE.L (A5),D0
BSR REMAPX
MOVE.L D0,X1
MOVE.L 4(A5),D0
BSR REMAPY
MOVE.L D0,Y1
MOVE.L 8(A5),COLOR
BSR DOLINE ;Draw line from X0,Y0 to X1,Y1
MOVE.L X1,X0 ;Resume where we left off
MOVE.L Y1,Y0
RTS
;-----------------------------------------------------------------------
;43
;Move to the start of a line.
; MOVE(X, Y)
;
MOVE MOVE.L (A5),D0
BSR REMAPX
MOVE.L D0,X0
MOVE.L 4(A5),D0
BSR REMAPY
MOVE.L D0,Y0
RTS
;======================================================================
;FLOATING POINT ROUTINES:
;-----------------------------------------------------------------------
;46
;Reserve heap space for a real array
; A5:= A5 + ARG *RLSIZE
; ADDR:= RLRES(REALS)
; The starting (low) address of the reserved space in returned in FP0.
;WARNING: This assumes that the heap and the stack are arranged so that
; they grow toward each other. This also assumes 8 bytes in a real.
;
RLRES MOVE.L A5,D0 ;Return the base address in FP0
DC.W $F200, $4000 ;FMOVE.L D0,FP0 (FLOAT)
MOVE.L (A5),D0 ;Get the number of reals to reserve
LSL.L #3,D0 ;Times 8 to get the number of bytes
ADDA.L D0,A5 ;Add the argument number of bytes
; to the heap pointer (A5)
CMPA.L SP,A5 ;Check for memory overflow
BLO.S RRES90
JSR VERROR
ASCII '103 - MEMORY OVERFLOW'
DC.B 0
RRES90 RTS
;-----------------------------------------------------------------------
;47
; X:= RLIN(DEV);
;
RLIN BRA BADINT
;-----------------------------------------------------------------------
;48
; RLOUT(DEV,X);
;
RLOUT BRA BADINT
;-----------------------------------------------------------------------
;49
;X:= FLOAT(I);
;(FMOVE.L -8(SP),FP0 is not implemented in FPP.68K)
;
FLOAT MOVE.L (A5),D0
DC.W $F200, $4000 ;FMOVE.L D0,FP0
RTS
;-----------------------------------------------------------------------
;50
;I:= FIX(X);
;
FIX DC.W $F215, $5400 ;FMOVE.D (A5),FP0
DC.W $F200, $6000 ;FMOVE.L FP0,D0
RTS
;-----------------------------------------------------------------------
;51
;X:= RLABS(X);
;
RLABS DC.W $F215, $5400 ;FMOVE.D (A5),FP0
DC.W $F200, $0018 ;FABS.X FP0
RTS
;-----------------------------------------------------------------------
;52
;FORMAT(M,N);
;
FORMAT BRA BADINT
;-----------------------------------------------------------------------
;53
;X:= SQRT(X);
;(FSQRT.D (A5),FP0 et cetra are not implemented in FPP.68K)
;
SQRT DC.W $F215, $5400 ;FMOVE.D (A5),FP0
DC.W $F200, $0004 ;FSQRT.X FP0
RTS
;-----------------------------------------------------------------------
;54
;X:= LN(X);
;
LN DC.W $F215, $5400 ;FMOVE.D (A5),FP0
DC.W $F200, $0014 ;FLOGN.X FP0
RTS
;-----------------------------------------------------------------------
;55
;X:= EXP(X);
;
EXP DC.W $F215, $5400 ;FMOVE.D (A5),FP0
DC.W $F200, $0010 ;FETOX.X FP0
RTS
;-----------------------------------------------------------------------
;56
;X:= SIN(X);
;
SIN DC.W $F215, $5400 ;FMOVE.D (A5),FP0
DC.W $F200, $000E ;FSIN.X FP0
RTS
;-----------------------------------------------------------------------
;57
;X:= ATAN2(Y,X);
;
ATAN2 BRA BADINT
;-----------------------------------------------------------------------
;58
;X:= MOD(A,B);
;
MOD BRA BADINT
;-----------------------------------------------------------------------
;59
;X:= LOG(X);
;
LOG DC.W $F215, $5400 ;FMOVE.D (A5),FP0
DC.W $F200, $0015 ;FLOG10.X FP0
RTS
;-----------------------------------------------------------------------
;60
;X:= COS(X);
;
COS DC.W $F215, $5400 ;FMOVE.D (A5),FP0
DC.W $F200, $001D ;FCOS.X FP0
RTS
;-----------------------------------------------------------------------
;61
;X:= TAN(X);
;
TAN DC.W $F215, $5400 ;FMOVE.D (A5),FP0
DC.W $F200, $000F ;FTAN.X FP0
RTS
;-----------------------------------------------------------------------
;62
;X:= ASIN(X);
;
ASIN DC.W $F215, $5400 ;FMOVE.D (A5),FP0
DC.W $F200, $000C ;FACOS.X FP0
RTS
;-----------------------------------------------------------------------
;63
;X:= ACOS(X);
;
ACOS DC.W $F215, $5400 ;FMOVE.D (A5),FP0
DC.W $F200, $001C ;FACOS.X FP0
RTS
;-----------------------------------------------------------------------
;64
;Set the backup flag, so the next CHIN will reread the same byte.
; BACKUP
;
BACKUP ST BACKFL ;Set on condition true, i.e. always
RTS
;======================================================================
;65
; HICHAR(X, Y, MODE, ROT, CHAR)
;
HICHAR RTS
;-----------------------------------------------------------------------
;66
;Return the value of the byte in the Apple at the given address
; BYTE:=PEEK(ADDRESS)
;
PEEK RTS
;-----------------------------------------------------------------------
;67
;Store the byte at the given address.
; POKE(ADDR,BYTE)
;
POKE RTS
;----------------------------------------------------------------------
;108
;Define the bit map location and dimensions for POINT, LINE and CLEAR.
; (Note that this bit map might not be displayed immediately.)
; BITMAP(ADDR, WIDTH, HEIGHT, DEPTH)
; ADDR is the memory location of bit map.
; Use: RESERVE(WIDTH /8 *HEIGHT *DEPTH)
; WIDTH should be either 320, 640, or a larger value up to 1024. It
; must always be evenly divisible by 16, because of CLEAR.
; HEIGHT should be in the range 200 through 1024.
; DEPTH should be in the range 1 through 6.
; WIDTH and HEIGHT should always be equal to or greater than the
; displayed view.
;
BITMAP MOVE.L (A5),RASTER
MOVE.L 4(A5),WIDTH
MOVE.L 8(A5),HEIGHT
MOVE.L 12(A5),DEPTH
; ANDI.W #$03FF,D0 ; after shifting right 4 bits
; BEQ.S CLR10 ;Branch if ok
; JSR VERROR
; ASCII "106 - BAD RASTER DIMENSIONS"
; DC.B 0
; BRA.S CLR60 ;Give it our best shot
;CLR10
RTS
;----------------------------------------------------------------------
;109
;Define the scale factors and offsets for coordinates used by POINT,
; LINE and CLEAR.
; BITMAP2(MAGX, MAGY, OFFSETX, OFFSETY, INVERTX, INVERTY)
;
BITMAP2 MOVE.L (A5),MAGX
MOVE.L 4(A5),MAGY
MOVE.L 8(A5),OFFSETX
MOVE.L 12(A5),OFFSETY
MOVE.L 16(A5),INVERTX
MOVE.L 20(A5),INVERTY
RTS
;----------------------------------------------------------------------
;110
; VIEW(ADDR, BPLCON0)
VIEW BRA DOVIEW ;(PBRA)
;----------------------------------------------------------------------
;111
; PALETTE(N, VAL)
PALETTE BRA DOPALET ;(PBRA)
;----------------------------------------------------------------------
;112
;Return the value of the extend (X) flag. This flag, effectively the
; carry flag, is used for extended-precision arithmetic.
; VAL:= CARRY(0)
;
CARRY MOVEQ #0,D0 ;Clear high bytes
ADDX.B D0,D0 ;Add the extend (carry) value (0 or 1)
RTS
;----------------------------------------------------------------------
;113
;Return the value of the word at the given address.
; WORD:= PEEK_W(ADDR)
;
PEEK_W MOVEA.L (A5),A6 ;Get the address
MOVEQ #0,D0 ;Clear high word
MOVE.W (A6),D0 ;Return the word in D0
RTS
;----------------------------------------------------------------------
;114
;Store the word at the given address.
; POKE_W(ADDR,WORD)
;
POKE_W MOVEA.L (A5),A6 ;Get the address
MOVE.W 6(A5),(A6) ;Store the word
RTS
;----------------------------------------------------------------------
;115
;Return the value of the long at the given address.
; LONG:= PEEK_L(ADDR)
;
PEEK_L MOVEA.L (A5),A6 ;Get the address
MOVE.L (A6),D0 ;Return the long in D0
RTS
;----------------------------------------------------------------------
;116
;Store the long word at the given address.
; POKE_L(ADDR,LONG)
;
POKE_L MOVEA.L (A5),A6 ;Get the address
MOVE.L 4(A5),(A6) ;Store the long
RTS
;----------------------------------------------------------------------
;117
;Swap the high and low words in the value and return it.
; VAL:= SWAP_W(VAL)
;
SWAP_W MOVE.L (A5),D0 ;Get the value
SWAP D0
RTS
;----------------------------------------------------------------------
;118
;Sign-extend the 16-bit value and return it.
; VAL:= EXT_L(VAL)
;
EXT_L MOVE.W 2(A5),D0
EXT.L D0
RTS
;----------------------------------------------------------------------
;119
;Move cursor on the second terminal (device #1) to column X, line Y.
; Upper left corner is X,Y = 0,0.
; CURSOR1(X,Y)
; A6 is destroyed.
;
CURSOR1 MOVE.B #1,DEVICE ;Set to device number 1
MOVE.B 3(A5),D0 ;Get X position
ROL.W #8,D0 ;Put it into high byte of D0
MOVE.B 7(A5),D0 ;Get Y position into low byte
MOVEA.W #28,A6 ;Set function code = "position cursor"
JMP VDEVHAN ;(PJMP) do I/O
;-----------------------------------------------------------------------
;120
;Set the display attributes for the second terminal (device #1)
; BUTES1($1);
;The bits in the argument set the attributes as follows:
; 0 - bold (not dim)
; 1 - underline
; 2 - inverse video
; 3 - flashing
;
;WARNING: The Wyse terminal is severely brain-damaged, and it insists on
; inserting a space character whenever attributes are changed.
;
BUTES1 MOVE.L (A5),D0 ;Get argument
MOVE.B #1,DEVICE ;Set to device # 1
MOVEA.W #48,A6 ;Set function code for "butes"
JMP VDEVHAN ;(PJMP) go do it
;-----------------------------------------------------------------------
;121
;Turn the cursor indicator on or off for the second terminal (device #1)
; SHOCUR1('TRUE');
;
SHOCUR1 MOVE.L (A5),D0 ;Get boolean argument
MOVE.B #1,DEVICE ;Set to device # 1
MOVEA.W #44,A6 ;Set function code for cursor control
JMP VDEVHAN ;(PJMP) go do it
;-----------------------------------------------------------------------
;122
;Return the address of the information array for a device
; ADDR:= DEVINFO(DEV)
;
DEVINFO MOVE.B 3(A5),DEVICE ;Get the device number
MOVEA.W #20,A6 ;Set function code for "getinfo"
JMP VDEVHAN ;(PJMP) go do it
;-----------------------------------------------------------------------
;123
;Return the address of the information array for a unit
; ADDR:= UNTINFO(UNIT)
;
UNTINFO MOVE.B 3(A5),UNIT ;Get the unit number
MOVEA.W #20,A6 ;Set function code for "getinfo"
JMP VUNTHAN ;(PJMP) go do it
;-----------------------------------------------------------------------
;124
;Set the display attributes for device 0
; BUTES($1);
;The bits in the argument set the attributes as follows:
; 0 - bold (not dim)
; 1 - underline
; 2 - inverse video
; 3 - flashing
;
;WARNING: The Wyse terminal is severely brain-damaged, and it insists on
; inserting a space character whenever attributes are changed.
;
BUTES MOVE.L (A5),D0 ;Get argument
MOVE.B #0,DEVICE ;Set to device # 0
MOVEA.W #48,A6 ;Set function code for "butes"
JMP VDEVHAN ;(PJMP) go do it
;-----------------------------------------------------------------------
;125
;Wait for and then return the value of a key struck on
; the keyboard
; I:= GETKEY;
;
GETKEY MOVE.B #1,DEVICE ;Set to device # 1
MOVEA.W #36,A6 ;Set function code for "getkey"
JMP VDEVHAN ;(PJMP) return with value in D0
;-----------------------------------------------------------------------
;126
;Determine if a key (on the keyboard) has been struck
; I:= KEYHIT;
;
KEYHIT MOVE.B #1,DEVICE ;Set to device # 1
MOVEA.W #40,A6 ;Set function code
JMP VDEVHAN ;(PJMP) return with boolean in D0
;-----------------------------------------------------------------------
;127
;Turn the cursor indicator on or off for device 0
; SHOCUR('TRUE');
;
SHOCUR MOVE.L (A5),D0 ;Get boolean argument
MOVE.B #0,DEVICE ;Set to device # 0
MOVEA.W #44,A6 ;Set function code for cursor control
JMP VDEVHAN ;(PJMP) go do it
;=======================================================================
;SUBROUTINES:
;-----------------------------------------------------------------------
;Input ASCII digits and convert them to a signed, decimal, 32-bit value
; which is returned in D0.
; D0 = I/O
; D1 = Working register (contains number to be converted)
; D2 = Flag: a numeric character has been entered
; D3 = 10 multiplier
; D4 = Flag: a minus sign was entered, i.e. the number is negative
;
INTI MOVEM.L D1-D4,-(SP) ;Save registers
II00 MOVEQ #0,D1 ;NUM:=0;
CLR.B D2 ;NUMFLG:=false
CLR.B D4 ;SIGN:=false
MOVEQ #10,D3
BSR BYTEIN ;Get byte
CMPI.B #'-',D0 ;if D0 = ^- then SIGN := true
BNE.S II30
MOVEQ #TRUE,D4
; ;loop begin
II20 BSR BYTEIN ;Get byte
II30 CMPI.B #'0',D0 ; if D0<^0 ! D0>^9 then quit
BLO.S II50
CMPI.B #'9',D0
BHI.S II50
MOVEQ #TRUE,D2 ; NUMFLG:=true
MOVE.L D1,D3 ; NUM:= NUM*10 + (D0-^0)
LSL.L #2,D1 ; *4
ADD.L D3,D1 ; +1
LSL.L #1,D1 ; *2
SUBI.B #'0',D0
ADD.L D0,D1
BRA.S II20 ; end
II50 TST.B D2 ;if NUMFLG then quit
BEQ.S II00
TST.B D4 ;if SIGN then NUM:= -NUM
BEQ.S II60
NEG.L D1
II60 MOVE.L D1,D0 ;return NUM
MOVEM.L (SP)+,D1-D4 ;Restore registers
RTS
;-----------------------------------------------------------------------
;Convert the signed, 32-bit value in D0 to decimal ASCII and output the
; characters to DEVICE.
; D0 = I/O and subtract counter
; D1 = Working register (contains number to be converted)
; D2 = Flag used to suppress leading zeros (suppress if false)
; D3 = Power-of-ten (loop) counter
; D4 = Power of ten
; A0 = Pointer to power-of-ten table
;
INTO MOVEM.L D0-D4/A0/A6,-(SP) ;Save registers
MOVEA.W #12,A6 ;Set the function code = CHOUT
MOVE.L D0,D1 ;Put number into the working register
BPL.S INTO10 ;Branch if it is positive
NEG.L D1 ;Otherwise make it positive
MOVEQ #'-',D0 ;Output the minus sign
JSR VDEVHAN ;Output D0
;Initialize:
INTO10 MOVEQ #FALSE,D2 ; flag used to suppress leading zeros
MOVEQ #8,D3 ; loop counter (8 down through 0)
LEA TENTBL-@-2(PC),A0 ; pointer to power-of-ten table
INTO20 MOVE.L (A0)+,D4 ;Get a power of ten
MOVEQ #9,D0 ;Init loop counter (9-0)
INTO30 SUB.L D4,D1 ;Repeatedly subtract a power of ten
DBMI D0,INTO30 ; until it goes negative
ADD.L D4,D1 ;Restore to positive value
NEG.B D0 ;This digit = 9 - D0
ADD.B #9,D0
BNE.S INTO40 ;Branch if digit is not zero
TST.B D2 ;Are we suppressing leading zeros?
BEQ.S INTO50 ;Branch if we are (i.e. flag = false)
INTO40 MOVEQ #TRUE,D2 ;Turn leading zero suppression off
ADD.B #'0',D0 ;Convert digit to ASCII
JSR VDEVHAN ;Output it
INTO50 DBF D3,INTO20 ;Repeat for powers 1,000,000,000 down
; thru 10;
MOVE.B D1,D0 ;Output the one's digit regardless of
ADD.B #'0',D0 ; the leading zero suppression flag
JSR VDEVHAN
MOVEM.L (SP)+,D0-D4/A0/A6 ;Restore registers
RTS
;Power-of-ten table:
TENTBL DC.L 1000000000 ;1G
DC.L 100000000
DC.L 10000000
DC.L 1000000 ;1M
DC.L 100000
DC.L 10000
DC.L 1000 ;1K
DC.L 100
DC.L 10
;-----------------------------------------------------------------------
;Output a text string pointed to by A6.
; The string is terminated with a binary zero.
;
TEXTO MOVEM.L A0/A6,-(SP) ;Save registers
MOVEA.L A6,A0 ;Get string address
MOVEA.W #12,A6 ;Set the function code to CHOUT
BRA.S TXT20 ;Enter loop
TXT10 JSR VDEVHAN ;Output D0
TXT20 MOVE.B (A0)+,D0 ;Get char from string
BNE.S TXT10 ;Loop until zero byte
MOVEM.L (SP)+,A0/A6 ;Restore registers
RTS
;-----------------------------------------------------------------------
;Input hex ASCII digits from DEVICE and convert them to a 32-bit value
; which is returned in D0.
; D0 = Digit
; D1 = Accumulated value
; D2 = Digit counter
;
HEXI MOVEM.L D1-D2,-(SP) ;Save registers
MOVEQ #0,D1 ;Clear result register
MOVEQ #7,D2 ;Init digit counter (7 down through 0)
HEXI00 BSR BYTEIN ;Get byte
CMPI.B #'0',D0 ;Is character in range 0 thru 9?
BLO.S HEXI40 ;Branch if not
CMPI.B #'9',D0
BHI.S HEXI20 ;(May be A-F)
SUBI.B #'0',D0 ;Convert ASCII to binary value
BRA.S HEXI30 ;Go combine with other digits
HEXI20 ANDI.B #$DF,D0 ;Force to uppercase
CMPI.B #'A',D0 ;Is character in range A thru F?
BLO.S HEXI40 ;Branch if not
CMPI.B #'F',D0
BHI.S HEXI40
SUBI.B #'A'-10,D0 ;Convert ASCII to binary value
HEXI30 ASL.L #4,D1 ;Multiply current value by 16
ADD.B D0,D1 ;Add new digit
DBF D2,HEXI00 ;Exit if we have 8 digits
HEXI40 CMPI.B #7,D2 ;Did we find a valid hex digit?
BEQ.S HEXI00 ;Branch if not -- keep trying
MOVE.L D1,D0 ;Return the hex value in D0
MOVEM.L (SP)+,D1-D2 ;Restore registers
RTS
;-----------------------------------------------------------------------
;Output D0 in ASCII hex (8 digits)
;
HEXO SWAP D0 ;Get high word
BSR.S WRDOUT ;Output it
SWAP D0 ;(PFALL) get low word back
;-----------------------------------------------------------------------
;Output D0 in ASCII hex (4 digits)
;
WRDOUT ROR.W #8,D0 ;Move high byte down (and save low byte)
BSR.S BYTOUT ;Output it
ROR.W #8,D0 ;(PFALL) get low byte
;-----------------------------------------------------------------------
;Output D0 in ASCII hex (2 digits)
;
BYTOUT ROR.B #4,D0 ;Move high nybble down (save low nybble)
BSR.S NYBOUT ;Output it
ROR.B #4,D0 ;(PFALL) get low nybble
;-----------------------------------------------------------------------
;Output D0 in ASCII hex (1 digit)
;
NYBOUT MOVEM.L D0/A6,-(SP) ;Save registers
ANDI.B #$0F,D0 ;Work with low nybble only
CMPI.B #10,D0
BLO.S NO10
ADDQ.B #7,D0
NO10 ADDI.B #'0',D0 ;Convert to ASCII
MOVEA.W #12,A6 ;Set the function code = CHOUT
JSR VDEVHAN ;Output D0
MOVEM.L (SP)+,D0/A6 ;Restore registers
RTS
;-----------------------------------------------------------------------
;Input a byte from DEVICE and return it in D0.
;
BYTEIN TST.B BACKFL ;Re-read the last character?
BEQ.S BYIN20 ;Branch if not
CLR.B BACKFL ;Clear backup flag
MOVEQ #0,D0
MOVE.B LASTCH,D0 ;Return the last character
RTS
BYIN20 MOVE.L A6,-(SP) ;Save A6
MOVEA.W #8,A6 ;Set the function code = CHIN
JSR VDEVHAN ;Do I/O
MOVE.B D0,LASTCH ;Save in case we need to re-read it
MOVEA.L (SP)+,A6 ;Restore A6
RTS
;======================================================================
;GRAPHICS ROUTINES
;
CHIPREG EQU $DFF000 ;Base address of chip registers
;Offsets to chip registers:
DMACONR EQU $02 ;DMA control (and blitter status) read
VPOSR EQU $04 ;Read vert. MSB and frame flop LOF
INTREQR EQU $1E ;Interrupt request bits read
BLTCON0 EQU $40 ;Blitter control register 0
BLTCON1 EQU $42 ;Blitter control register 1
BLTAFWM EQU $44 ;Blitter first word mask for source A
BLTCPTH EQU $48 ;Blitter ptr to source C (high 3 bits)
BLTAPTH EQU $50 ;Blitter ptr to source A (high 3 bits)
BLTAPTL EQU $52 ;Blitter ptr to source A (low 15 bits)
BLTDPTH EQU $54 ;Blitter ptr to destn. D (high 3 bits)
BLTSIZE EQU $58 ;Blitter start and size (width, height)
BLTCMOD EQU $60 ;Blitter modulo for source C
BLTBMOD EQU $62 ;Blitter modulo for source B
BLTAMOD EQU $64 ;Blitter modulo for source A
BLTDMOD EQU $66 ;Blitter modulo for destn. D
BLTBDAT EQU $72 ;Blitter source B data register
BLTADAT EQU $74 ;Blitter source A data register
COP1LCH EQU $80 ;Copper 1st location reg (high 3 bits)
COP1LCL EQU $82 ;Copper 1st location reg (low 15 bits)
DIWSTRT EQU $8E ;Display window start
DIWSTOP EQU $90 ;Display window stop
DDFSTRT EQU $92 ;Display bit plane data fetch start
DDFSTOP EQU $94 ;Display bit plane data fetch stop
DMACON EQU $96 ;DMA control write (clear or set)
INTENA EQU $9A ;Interrupt enable bits (clear or set)
INTREQ EQU $9C ;Interrupt request bits (clear or set)
BPL1PTH EQU $E0 ;Bit plane 1 pointer (high 3 bits)
BPLCON0 EQU $100 ;Bit plane control register 0
BPLCON1 EQU $102 ;Bit plane control register 1
BPLCON2 EQU $104 ;Bit plane control register 2
BPL1MOD EQU $108 ;Bit plane modulo (odd planes)
BPL2MOD EQU $10A ;Bit plane modulo (even planes)
COLOR00 EQU $180 ;Color register 00
COLOR01 EQU $182 ;Color register 01
;----------------------------------------------------------------------
;107
;Wait for vertical blank on the video screen
;
WAITVB MOVE.W #$0020,INTREQ+CHIPREG.L
WVB10 MOVE.W INTREQR+CHIPREG.L,D0
BTST #5,D0
BEQ.S WVB10
RTS
;----------------------------------------------------------------------
;Remap the X coordinate in D0.
;
REMAPX MOVE.W D1,-(SP) ;Save D1
MOVE.W MAGX+2,D1 ;Get the magnification factor
BEQ.S RMX20 ;Branch if no magnification
BGE.S RMX10 ;Branch if it's increasing in size
NEG.W D1 ;It's decreasing in size
ASR.L D1,D0
BRA.S RMX20
RMX10 ASL.L D1,D0
RMX20
ADD.L OFFSETX,D0 ;Add offset
TST.L INVERTX ;Is X increasing to the left?
BEQ.S RMX30 ;Branch if not
NEG.L D0 ;D0:= WIDTH - D0
ADD.L WIDTH,D0
RMX30
MOVE.W (SP)+,D1 ;Restore D1
RTS ;Return with remapped value in D0
;----------------------------------------------------------------------
;Remap the Y coordinate in D0.
;
REMAPY MOVE.W D1,-(SP) ;Save D1
MOVE.W MAGY+2,D1 ;Get the magnification factor
BEQ.S RMY20 ;Branch if no magnification
BGE.S RMY10 ;Branch if it's increasing in size
NEG.W D1 ;It's decreasing in size
ASR.L D1,D0
BRA.S RMY20
RMY10 ASL.L D1,D0
RMY20
ADD.L OFFSETY,D0 ;Add offset
TST.L INVERTY ;Is Y increasing upward?
BEQ.S RMY30 ;Branch if not
NEG.L D0 ;D0:= HEIGHT - D0
ADD.L HEIGHT,D0
RMY30
MOVE.W (SP)+,D1 ;Restore D1
RTS ;Return with remapped value in D0
;----------------------------------------------------------------------
;This sets up a copper list to display the bit map whos upper-left
; corner is at ADDR. It sets the bit plane control register, BPLCON0,
; directly, and from this the display's width, height, and depth are
; determined. The bit map's WIDTH and HEIGHT are assumed to have been
; set. (These are used to determine modulo and size when DEPTH is
; greater than one.) ADDR should be an even address (RESERVE will
; automatically do this.)
;This routine handles the common displays, however it does not handle
; dual playfields, or horizontal scrolling. These may be accomplished
; by setting the chip registers directly.
;
; VIEW(ADDR, BPLCON0)
; BPLCON0 bits:
; 15 HIRES 11 HAM 07 -- 03 LPEN
; 14 BPU2 10 DBLPF 06 -- 02 LACE
; 13 BPU1 09 COLOR 05 -- 01 ERSYNC
; 12 BPU0 08 GAUD 04 -- 00 --
;
; Register usage:
; D0 = BPLCON0 and scratch
; D1 = Size of each bit plane in bytes
; D2 = Modulo and depth of bit planes
; D3 = Display data fetch (DDF) and bit plane pointers (BPLxPT)
; D4 = View address (ADDR)
; A0 = Base address of chip registers (CHIPREG)
; A1 = Copper list pointer
; A2 = Start of even copper list
; A3 = Start of odd copper list (if interlaced display)
;
;
DOVIEW MOVEM.L D0-D4/A0-A3,-(SP) ;Save registers
LEA CHIPREG.L,A0 ;Point A0 to base of chip registers
MOVE.L (A5),D4 ;Get view address (ADDR)
MOVE.W 6(A5),D0 ;Get BPLCON0
MOVE.W D0,BPLCON0(A0) ; and set it
MOVE.W WIDTH+2,D2 ;Set the modulo...
LSR.W #3,D2 ;Divide by 8 to convert bits to bytes
MOVE.W D2,D1 ;Save width in bytes for later
SUB.W #40,D2 ;Anticipate LOWRES mode
MOVE.L #$00D00038,D3 ;Set LOWRES DDF stop and start positions
BTST #15,D0 ;Is it HIRES mode?
BEQ.S VIEW10 ;Branch if not
SUB.W #40,D2 ;Account for another 40 bytes of width
MOVE.L #$00D4003C,D3 ;HIRES DDF stop and start positions
VIEW10
BTST #2,D0 ;Is interlace requested?
BEQ.S VIEW20 ;Branch if not
ADD.W D1,D2 ;Skip every other line of bit plane
VIEW20
MOVE.W D2,BPL1MOD(A0) ;Set modulo
MOVE.W D2,BPL2MOD(A0) ;Set unused modulo to known state
MOVE.W D3,DDFSTRT(A0) ;Set display data fetch horz start posn
SWAP D3 ;Get stop position
MOVE.W D3,DDFSTOP(A0) ; and set it
MOVE.W #$1781,DIWSTRT(A0) ;Set display window start and stop
MOVE.W #$07C1,DIWSTOP(A0) ; horizontal and vertical positions
MOVEQ #0,D2 ;(Warning: CLR.W does a read cycle)
MOVE.W D2,BPLCON1(A0) ;Initialize these unused registers to
MOVE.W D2,BPLCON2(A0) ; a known state
MOVE.W #$8380,DMACON(A0) ;Make sure bit plane and copper DMA
; are on
;Set up the copper list:
MULU HEIGHT+2,D1 ;D1 = size of each bit plane, in bytes
MOVE.W D0,D2 ;D2 = number of bit planes used (depth)
ROL.W #4,D2 ;Get BPU bits from BPLCON0
AND.W #0007,D2
LEA COPLST1,A1 ;Point A1 to first copper list area
BTST #0,COPFLAG ;Is this list busy?
BEQ.S VIEW30 ;Branch if not
LEA COPLST2,A1 ;Point A1 to second copper list area
VIEW30 ADDQ.B #1,COPFLAG ;Flip busy flag
MOVEA.L A1,A2 ;Save (even) copper list address
BSR.S VIEW100 ;Set up copper list
BTST #2,D0 ;Is display interlaced?
BEQ.S VIEW80 ;Branch if not
MOVE.W #COP1LCL,D0 ;Set up call for odd copper list
SWAP D0
MOVE.W A1,D0 ;Get odd copper list address
ADDQ.W #8,D0 ;Past this and next instructions
MOVE.L D0,(A1)+
MOVEQ #$FFFFFFFE,D0 ;Terminate even copper list with
MOVE.L D0,(A1)+ ; wait-forever command
MOVEA.L A1,A3 ;Save address of odd copper list
MOVE.L WIDTH,D0 ;Point to second (odd) display line
LSR.L #3,D0 ;Divide by 8 to convert bits to bytes
ADD.L D0,D4
BSR.S VIEW100 ;Set up odd copper list
MOVE.W #COP1LCL,D0 ;Set up call to even copper list
SWAP D0
MOVE.W A2,D0 ;Get even copper list address
MOVE.L D0,(A1)+
MOVEQ #$FFFFFFFE,D0 ;Terminate with wait-forever command
MOVE.L D0,(A1)+
MOVE.W VPOSR(A0),D0 ;Is current frame long (even)?
BPL.S VIEW50 ;Branch if not -- branch if odd frame
EXG A2,A3 ;Current frame is even, next will be odd
VIEW50 MOVE.L A2,COP1LCH(A0)
MOVE.W VPOSR(A0),D1 ;Did vertical blank occur during last
EOR.W D1,D0 ; few instructions (LOF change)?
BPL.S VIEW90 ;Branch if not
MOVE.L A3,COP1LCH(A0) ;Current frame is odd, next will be even
BRA.S VIEW90
;Here if non-interlaced display
VIEW80 MOVEQ #$FFFFFFFE,D0 ;Terminate with wait-forever command
MOVE.L D0,(A1)+
;This new copper list will be used at the next vertical sync. All copper
; lists must be in the same 64K "page" to prevent a possible big glitch.
MOVE.L A2,COP1LCH(A0)
VIEW90 MOVEM.L (SP)+,D0-D4/A0-A3 ;Restore registers
RTS
;----------------------------------------------------------------------
;Routine to set up a copper list.
;Inputs:
; D1 = Bit plane size (bytes)
; D2 = Number of bit planes (depth)
; D4 = View address (ADDR)
; A1 = Copper list address pointer
;
;
VIEW100 MOVEM.L D2/D4,-(SP) ;Save some registers
MOVE.W #BPL1PTH,D3 ;Set to first bit-plane pointer register
BRA.S VIEW130 ;Enter loop checking for zero (be safe)
VIEW120 MOVE.W D3,(A1)+ ;Put pointer register into copper list
ADDQ.W #2,D3 ;Next pointer register
SWAP D4 ;Get the high word of view address
MOVE.W D4,(A1)+ ;Put it into copper list
SWAP D4
MOVE.W D3,(A1)+ ;Put pointer register into copper list
ADDQ.W #2,D3 ;Next pointer register
MOVE.W D4,(A1)+ ;Put low word of view address into list
ADD.L D1,D4 ;Add bit-plane size to view address
VIEW130 DBF D2,VIEW120 ;Loop for all bit planes
MOVEM.L (SP)+,D2/D4 ;Restore some registers
RTS
;----------------------------------------------------------------------
;Set color register N to value VAL.
; PALETTE(N, VAL)
;
DOPALET MOVEQ #0,D0 ;Get the color register number
MOVE.B 3(A5),D0 ; (limit to 256 color regs for safety)
ADD.W D0,D0 ;Double for word entries
ADD.W #COLOR00,D0 ;Add base address of color registers
LEA CHIPREG.L,A6
MOVE.W 6(A5),0(A6,D0.W) ;Set color register's value
RTS
;----------------------------------------------------------------------
;Routine to clear the current bit map by setting it to the color
; defined by color register 0. It also moves X0,Y0 to 0,0.
; The blitter uses every other even memory cycle to clear memory. This
; allows the 68000 to run simultaneously. Maximum efficiency is achieved
; if the 68000 doesn't immediately call LINE or POINT since these
; operations will require waiting for the blitter. This will clear a
; 640x480x1 bitmap in approximately 1/75th of a second.
;
;This simply clears the number of words equal to WIDTH/16 *HEIGHT *DEPTH
; The blitter can clear a maximum of 128K bytes per pass.
;
DOCLEAR MOVEM.L D0/D1/A0,-(SP) ;Save registers
LEA CHIPREG.L,A0 ;Set register base (it's efficient)
MOVE.W #$8640,DMACON(A0) ;Enable blitter DMA and be nasty
MOVE.W WIDTH+2,D1 ;No. of words = WIDTH/16 *DEPTH *HEIGHT
MULU DEPTH+2,D1 ;(This product must not exceed 65535)
MULU HEIGHT+2,D1
LSR.L #4,D1 ;Divide by 16 to get number of words
BSR WAITBLT ;Wait for blitter not busy
MOVE.L RASTER,BLTDPTH(A0) ;Point to location to be cleared
MOVEQ #0,D0 ;(Warning: CLR.W does a read)
MOVE.W D0,BLTDMOD(A0) ;Modulo = 0
MOVE.W #$0100,BLTCON0(A0) ;Use destination D only
MOVE.W D0,BLTCON1(A0)
MOVE.W D1,D0 ;Is there a small chunk <$1000 to clear?
BEQ.S CLR25 ;Branch if not
ANDI.W #$003F,D0 ;Is there a chunk <64 words to clear?
BEQ.S CLR22 ;Branch if not
ORI.W #$0040,D0 ;Clear chunk with height =1 & width =D0
MOVE.W D0,BLTSIZE(A0)
CLR22
ANDI.W #$FFC0,D1 ;Is $40 <= chunk <$10000?
BEQ.S CLR25 ;Branch if not
BSR WAITBLT
MOVE.W D1,BLTSIZE(A0) ;Clear chunk: hight=D1/64, width=64 words
CLR25
SWAP D1 ;D1.W:= number of $10000 chunks to clear
BRA.S CLR50 ;Enter loop checking for zero chunks
CLR30
BSR WAITBLT ;Wait for blitter not busy
MOVE.W #0,BLTSIZE(A0) ;Clear 128K bytes, and advance BLTDPTH
; (128K bytes = $10000 words)
CLR50 DBF D1,CLR30 ;Loop for next $10000 chunk
CLR60 MOVEQ #0,D0 ;MOVE(0,0)
MOVE.L D0,X0
MOVE.L D0,Y0
MOVEM.L (SP)+,D0/D1/A0 ;Restore registers
RTS
;----------------------------------------------------------------------
;Routine to plot a point at X0,Y0 of the given COLOR.
; The upper-left corner is coordinate 0,0, and the positive Y direction
; is down (this might have been remapped by BITMAP2).
;
DOPOINT MOVEM.L D0-D3/A6,-(SP) ;Save registers
MOVE.L X0,D1 ;Clip points outside bit map
BMI.S DOPT90
CMP.L WIDTH,D1
BGE.S DOPT90
MOVE.L Y0,D0 ;BYTE = (X0 + Y0*WIDTH) /8 + RASTER
BMI.S DOPT90 ;D0 =
CMP.L HEIGHT,D0
BGE.S DOPT90
MULU WIDTH+2,D0 ; * Y0
ADD.L D1,D0 ; + X0
LSR.L #3,D0 ; / 8
MOVEQ #7,D1 ;BIT = 7 - REM(X0/8)
SUB.B X0+3,D1
MOVE.W WIDTH+2,D3 ;D3 = SIZE = WIDTH *HEIGHT
MULU HEIGHT+2,D3
LSR.L #3,D3 ;Divide by 8 to get size in bytes
LEA CHIPREG.L,A6 ;Set register base (it's efficient)
DOPT05 MOVE.W DMACONR(A6),D2 ;Wait for blitter not busy, because it
BTST #14,D2 ; might be doing a CLEAR
BNE.S DOPT05
MOVEA.L RASTER,A6
MOVEQ #0,D2
DOPT10 BTST #0,MODES
BNE.S DOPT40 ;Branch if complement mode
BTST D2,COLOR+3 ;Plot the point in the current screen
BEQ.S DOPT20 ; if the corresponding COLOR bit is set
BSET D1,0(A6,D0.L) ;(D1 is modulo 8)
BRA.S DOPT30
DOPT20 BTST #1,MODES
BNE.S DOPT50 ;Branch if fast mode
BCLR D1,0(A6,D0.L) ;(D1 is modulo 8)
DOPT30 BRA.S DOPT50
DOPT40 BCHG D1,0(A6,D0.L) ;(D1 is modulo 8)
DOPT50 ADDA.L D3,A6 ;Next bit plane -- add SIZE to ADDR
ADDQ.W #1,D2 ;(DBF will not work)
CMP.W DEPTH+2,D2
BLT.S DOPT10
DOPT90 MOVEM.L (SP)+,D0-D3/A6 ;Restore registers
RTS
;----------------------------------------------------------------------
;Routine to draw a line from X0,Y0 to X1,Y1.
; This routine first checks to see if the line falls outside the RASTER
; dimensions. If it does, the line is clipped and only the portion
; within the RASTER is drawn. The blitter in line-drawing mode, which
; plots a point every 2.24 microseconds.
; The upper-left corner is coordinate 0,0, and the positive Y direction
; is down (this might have been remapped by BITMAP2).
;
; Register usage (for clip, and for line):
; D0 = Scratch Scratch
; D1 = Scratch BLTSIZE
; D2 = Code 0 Bit plane
; D3 = Code 1 BLTCON0
; D4 = X0 RASTER size in bytes
; D5 = Y0 BLTCPTH & BLTDPTH, address of start of line
; D6 = X1 BLTAPTL
; D7 = Y1 BLTCON1
;
;
DOLINE MOVEM.L D0-D7/A0,-(SP) ;Save registers
;Clip lines to the RASTER dimensions:
MOVE.L X0,D4 ;Load registers with line end points
MOVE.L Y0,D5
MOVE.L Y1,D7
MOVEQ #0,D3 ;Initialize flag bits
MOVE.L X1,D6
SMI D3 ;Code 1 (X1LO, X1HI, Y1LO, Y1HI)
ADD.W D3,D3 ;D3 Bits: 10 9 8 7-0
CMP.L WIDTH,D6
SGE D3
ADD.W D3,D3 ;Shift left
TST.L D7
SMI D3
ADD.W D3,D3
CMP.L HEIGHT,D7
SGE D3
MOVEQ #0,D2 ;Initialize flag bits
TST.L D4 ;Code 0 (X0LO, X0HI, Y0LO, Y0HI)
SMI D2 ;D2 Bits: 10 9 8 7-0
ADD.W D2,D2
CMP.L WIDTH,D4
SGE D2
ADD.W D2,D2
TST.L D5
SMI D2
ADD.W D2,D2
CMP.L HEIGHT,D5
SGE D2
MOVE.W D2,D0 ;Is the line completely inside of the
OR.W D3,D0 ; RASTER area?
BEQ LINE00 ;Branch if it is -- draw it
MOVE.W D2,D0 ;Is the line completely outside of the
AND.W D3,D0 ; RASTER area?
BNE LINE90 ;Branch if it is -- forget it
;Handle points outside 16-bit arithmetic range by dividing both X and Y
; by 2 until they are within range.
MOVE.L D4,D1 ;Get X0 into D1
BPL.S CLIP010 ;Work with positive value
NEG.L D1
CLIP010
MOVE.L D5,D2 ;Get Y0 into D2
BPL.S CLIP020 ;Work with positive value
NEG.L D2
CLIP020
MOVE.L #$4000,D0 ;Are X0 and Y0 within 16 bit range?
CMP.L D0,D1
BHS.S CLIP030 ;Branch if not (beware of $80000000)
CMP.L D0,D2
BLO.S CLIP060 ;Branch if they are
CLIP030
MOVEQ #31,D0 ;Scan for most significant bit
CLIP040 BTST D0,D1 ;(Some bit from 14 up to 31 is set)
BNE.S CLIP050 ;Exit loop when found
BTST D0,D2
DBNE D0,CLIP040
CLIP050
SUB.B #13,D0 ;Bits 0-13 are within range
ASR.L D0,D4 ;Divide X0 and Y0 by 2 until they are
ASR.L D0,D5 ; within 16-bit arithmetic range
CLIP060
MOVE.L D6,D1 ;Repeat for X1, Y1...
BPL.S CLIP110
NEG.L D1
CLIP110
MOVE.L D7,D2
BPL.S CLIP120
NEG.L D2
CLIP120
MOVE.L #$4000,D0
CMP.L D0,D1
BHS.S CLIP130
CMP.L D0,D2
BLO.S CLIP160
CLIP130
MOVEQ #31,D0
CLIP140 BTST D0,D1
BNE.S CLIP150
BTST D0,D2
DBNE D0,CLIP140
CLIP150
SUB.B #13,D0
ASR.L D0,D6
ASR.L D0,D7
CLIP160
;At this point all points are within 16-bit arithmetic range.
MOVEQ #0,D3 ;Initialize flag bits
TST.W D6 ;Code 0 (X0LO, X0HI, Y0LO, Y0HI)
SMI D3 ;D3 Bits: 10 9 8 7-0
ADD.W D3,D3
CMP.W WIDTH+2,D6
SGE D3
ADD.W D3,D3
TST.W D7
SMI D3
ADD.W D3,D3
CMP.W HEIGHT+2,D7
SGE D3
CLIP200 MOVEQ #0,D2 ;Initialize flag bits
TST.W D4 ;Code 0 (X0LO, X0HI, Y0LO, Y0HI)
SMI D2 ;D2 Bits: 10 9 8 7-0
ADD.W D2,D2
CMP.W WIDTH+2,D4
SGE D2
ADD.W D2,D2
TST.W D5
SMI D2
ADD.W D2,D2
CMP.W HEIGHT+2,D5
SGE D2
MOVE.W D2,D0 ;Is the line completely inside of the
OR.W D3,D0 ; RASTER area?
BEQ LINE00 ;Branch if it is -- draw it
MOVE.W D2,D0 ;Is the line completely outside of the
AND.W D3,D0 ; RASTER area?
BNE LINE90 ;Branch if it is -- forget it
TST.W D2 ;Make sure that point X0,Y0 is outside
BNE.S CLIP210 ; the RASTER area
EXG D4,D6 ;Swap points
EXG D5,D7
EXG D2,D3 ;Swap codes
CLIP210
TST.B D2 ;Is point X0,Y0 beyond the bottom?
BEQ.S CLIP220 ;Branch if it is not
SUB.W D6,D4 ;Clip line at bottom edge of RASTER
MOVE.W HEIGHT+2,D1 ;X0:= X1 + (X0 - X1) * (HEIGHT-1 - Y1) /
SUBQ.W #1,D1 ; (Y0 - Y1)
MOVE.W D1,D2 ;D4:= D6 + (D4 - D6) * (HEIGHT-1 - D7) /
SUB.W D7,D1 ; (D5 - D7)
MULS D1,D4
SUB.W D7,D5
DIVS D5,D4
ADD.W D6,D4
MOVE.W D2,D5 ;Y0:= HEIGHT -1
BRA.S CLIP200
CLIP220
BTST #8,D2 ;Is point X0,Y0 above the top?
BEQ.S CLIP230 ;Branch if it is not
SUB.W D6,D4 ;Clip line at top edge of RASTER
MULS D7,D4 ;X0:= X1 + (X0 - X1) * Y1 / (Y1 - Y0)
MOVE.W D7,D1 ;D4:= D6 + (D4 - D6) * D7 / (D7 - D5)
SUB.W D5,D1
DIVS D1,D4
ADD.W D6,D4
CLR.W D5 ;Y0:= 0
BRA.S CLIP200
CLIP230
BTST #9,D2 ;Is point X0,Y0 beyond the right edge?
BEQ.S CLIP240 ;Branch if it is not
SUB.W D7,D5 ;Clip line at right edge of RASTER
MOVE.W WIDTH+2,D1 ;Y0:= Y1 + (Y0 - Y1) * (WIDTH-1 - X1) /
SUBQ.W #1,D1 ; (X0 - X1)
MOVE.W D1,D2 ;D5:= D7 + (D5 - D7) * (WIDTH-1 - D6) /
SUB.W D6,D1 ; (D4 - D6)
MULS D1,D5
SUB.W D6,D4
DIVS D4,D5
ADD.W D7,D5
MOVE.W D2,D4 ;X0:= WIDTH -1
BRA CLIP200
CLIP240 ;Pt. X0,Y0 must be left of the left edge
SUB.W D7,D5 ;Clip line at left edge of RASTER
MULS D6,D5 ;Y0:= Y1 + (Y0 - Y1) * X1 / (X1 - X0)
MOVE.W D6,D1 ;D5:= D7 + (D5 - D7) * D6 / (D6 - D4)
SUB.W D4,D1
DIVS D1,D5
ADD.W D7,D5
CLR.W D4 ;X0:= 0
BRA CLIP200 ;Loop a maximum of four times
;Draw the line:
LINE00 LEA CHIPREG.L,A0 ;Set register base (it's efficient)
MOVE.W #$8640,DMACON(A0) ;Enable blitter DMA and be nasty
BSR WAITBLT ;Wait for blitter not busy
MOVEQ #0,D0 ;Initialize octant value
MOVE.W D6,D1 ;Calculate delta X
SUB.W D4,D1
BPL.S LINE10 ;Branch if positive
NEG.W D1 ;Make it positive
BSET #0,D0 ;Indicate negative X octants
LINE10
MOVE.W D7,D2 ;Calculate delta Y
SUB.W D5,D2
BPL.S LINE20 ;Branch if positive
NEG.W D2 ;Make it positive
BSET #1,D0 ;Indicate negative Y octants
LINE20
CMP.W D1,D2 ;Is delta Y <= delta X
BLS.S LINE30 ;Branch if so
EXG D1,D2 ;Exchange X and Y, so Y is smaller
BSET #2,D0 ;Indicate reversed octants
LINE30
MOVE.B LINETBL-@-2(PC,D0.W),D0 ;Get octant control code
MOVE.W D0,D7 ;Save it in D7 (high byte must also
BRA.S LINE35 ; be clear)
;Table to convert our octant code to Amiga's octant command.
; Also sets LINE mode and SIGN flag.
LINETBL DC.B $51 ;0
DC.B $55 ;1
DC.B $59 ;2
DC.B $5D ;3
DC.B $41 ;4
DC.B $49 ;5
DC.B $45 ;6
DC.B $4D ;7
LINE35
MOVE.W D2,D6 ;2Y - X
ADD.W D6,D6
SUB.W D1,D6 ;Save result in D6 for BLTAPTL
MOVE.W D2,D0 ;4Y
ASL.W #2,D0
MOVE.W D0,BLTBMOD(A0)
MOVE.W D2,D0 ;4Y - 4X = (Y - X) *4
SUB.W D1,D0
ASL.W #2,D0
MOVE.W D0,BLTAMOD(A0)
ADDQ.W #1,D1 ;Adjust length to include end point
LSL.W #6,D1 ;Get line length (X) for the height
ADD.W #2,D1 ;Set width to 2, save in D1 for BLTSIZE
MOVE.W WIDTH+2,D0 ;Set no. of bytes per horizontal line
LSR.W #3,D0
MOVE.W D0,BLTCMOD(A0)
MOVE.W D0,BLTDMOD(A0)
MOVE.W TEXTURE,D0 ;Set texture mask
NOT.W D0 ;(A zero gives a solid line)
MOVE.W D0,BLTBDAT(A0)
MULU WIDTH+2,D5 ;Calculate address at start of line
EXT.L D4 ;ADDR = (X0 + Y0 *WIDTH) /8 + RASTER
ADD.L D4,D5
ASR.L #3,D5
ADD.L RASTER,D5
MOVE.W D4,D3 ;Get the bit shift count: REM(X0 /16)
SWAP D3 ; and put it into bits 12-15 of D3
MOVE.W #$B000,D3 ;Set up for BLTCON0 (line draw)
LSR.L #4,D3
MOVE.W WIDTH+2,D4 ;D4 = size = WIDTH *HEIGHT
MULU HEIGHT+2,D4
LSR.L #3,D4 ;Divide by 8 to get size in bytes
MOVEQ #0,D2 ;Depth counter, point to first bit plane
LINE40 BTST #0,MODES ;Is it complement mode?
BEQ.S LINE50 ;Branch if not
MOVE.B #$4A,D3 ;Set complement mode
BRA.S LINE60
LINE50
BTST D2,COLOR+3 ;Is the bit to be set in this bit plane?
BEQ.S LINE55 ;Branch if not
MOVE.B #$EA,D3 ;Set normal mode
BRA.S LINE60
LINE55
BTST #1,MODES ;Is this fast mode?
BNE.S LINE80 ;Branch if so (assume zeros are drawn)
MOVE.B #$2A,D3 ;Erase mode (draw zeros)
LINE60
BSR WAITBLT ;Wait for blitter not busy
MOVE.W D3,BLTCON0(A0) ;Set line draw mode (line function)
MOVE.W D7,BLTCON1(A0)
MOVE.W #$8000,BLTADAT(A0) ;Set dot mask
MOVE.W D6,BLTAPTL(A0) ;2Y - X
MOVE.L D5,BLTCPTH(A0) ;Point to address at the beginning
MOVE.L D5,BLTDPTH(A0) ; of the line
MOVE.W D1,BLTSIZE(A0) ;Start the blitter
LINE80 ADD.L D4,D5 ;Next bit plane -- add size to addr
ADDQ.W #1,D2 ;(DBF will not work)
CMP.W DEPTH+2,D2
BLT.S LINE40
LINE90 MOVEM.L (SP)+,D0-D7/A0 ;Restore registers
RTS
;----------------------------------------------------------------------
;Routine to wait until the blitter is not busy.
; Inputs A0 = CHIPREG
; Destroys D0
;
WAITBLT MOVE.W DMACONR(A0),D0 ;Wait for blitter not busy
BTST #14,D0 ;(Don't change the blitter's registers
BNE.S WAITBLT ; while it's doing something)
RTS
IF @ > MEMTOP - $3000 -$200
ERROR -- TOO BIG
ENDIF
END
sters